﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WebWorkContext.cs" company="">
//   
// </copyright>
// <summary>
//   Work context for web application
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Skymate.Mvc
{
    using System;
    using System.Web;

    using Skymate.Mvc.Extensions;
    using Skymate.Services.Authentication;

    /// <summary>
    ///     Work context for web application
    /// </summary>
    public class WebWorkContext : IWorkContext
    {
        /// <summary>
        /// The customer cookie name.
        /// </summary>
        private const string CustomerCookieName = "skymate.customer";

        /*private readonly ICustomerService _customerService;
		private readonly IStoreContext _storeContext;*/

        /// <summary>
        /// The _authentication service.
        /// </summary>
        private readonly IAuthenticationService _authenticationService;

        /// <summary>
        /// The _http context.
        /// </summary>
        private readonly HttpContextBase _httpContext;

        /*private readonly ILanguageService _languageService;
        private readonly ICurrencyService _currencyService;
		private readonly IGenericAttributeService _attrService;
        private readonly TaxSettings _taxSettings;
        private readonly CurrencySettings _currencySettings;
        private readonly LocalizationSettings _localizationSettings;
        private readonly ICacheManager _cacheManager;
        private readonly IStoreService _storeService;
        private readonly ISettingService _settingService;
		private readonly Lazy<ITaxService> _taxService;
		private readonly IUserAgent _userAgent;
*/
        /*private TaxDisplayType? _cachedTaxDisplayType;
        private Language _cachedLanguage;
        private Customer _cachedCustomer;*/
        /*private Currency _cachedCurrency;
        private Customer _originalCustomerIfImpersonated;*/

        /// <summary>
        /// The _cached customer.
        /// </summary>
        private string _cachedCustomer;

        /// <summary>
        /// The _is admin.
        /// </summary>
        private bool? _isAdmin;

        /*        Func<string, ICacheManager> cacheManager,
            HttpContextBase httpContext,
            ICustomerService customerService,
            IStoreContext storeContext,
            IAuthenticationService authenticationService,
            ILanguageService languageService,
            ICurrencyService currencyService,
            IGenericAttributeService attrService,
            TaxSettings taxSettings, CurrencySettings currencySettings,
            LocalizationSettings localizationSettings, Lazy<ITaxService> taxService,
            IStoreService storeService, ISettingService settingService,
			IUserAgent userAgent*/

        /// <summary>
        /// Initializes a new instance of the <see cref="WebWorkContext"/> class.
        /// </summary>
        /// <param name="httpContext">
        /// The http context.
        /// </param>
        /// <param name="authenticationService">
        /// The authentication service.
        /// </param>
        public WebWorkContext(HttpContextBase httpContext, IAuthenticationService authenticationService)
        {
            this._httpContext = httpContext;
            this._authenticationService = authenticationService;

            /*this._cacheManager = cacheManager("static");
            this._httpContext = httpContext;
            this._customerService = customerService;
			this._storeContext = storeContext;
            this._authenticationService = authenticationService;
            this._languageService = languageService;
			this._attrService = attrService;
            this._currencyService = currencyService;
            this._taxSettings = taxSettings;
			this._taxService = taxService;
            this._currencySettings = currencySettings;
            this._localizationSettings = localizationSettings;
            this._storeService = storeService;
            this._settingService = settingService;
			this._userAgent = userAgent;*/
        }

        // public Lazy<ITaxService> TaxService { get; set; }

        /// <summary>
        ///     Gets or sets the current customer
        /// </summary>
        public string CurrentCustomer
        {
            get
            {
                if (this._cachedCustomer != null)
                {
                    return this._cachedCustomer;
                }

                /*Customer customer = null;
*/
                // check whether request is made by a background task
                // in this case return built-in customer record for background task
                if (this._httpContext == null /*|| this._httpContext.IsFakeContext()*/)
                {
                    return string.Empty;

                    /*customer = this._customerService.GetCustomerBySystemName(SystemCustomerNames.BackgroundTask);*/
                }

                // check whether request is made by a search engine
                // in this case return built-in customer record for search engines 
                /*if (customer == null || customer.Deleted || !customer.Active)
                {
					if (this._userAgent.IsBot)
					{
						customer = this._customerService.GetCustomerBySystemName(SystemCustomerNames.SearchEngine);
					}
                }*/

                // check whether request is made by the PDF converter
                // in this case return built-in customer record for the converter
                /*if (customer == null || customer.Deleted || !customer.Active)
				{
					if (this._userAgent.IsPdfConverter)
					{
						customer = this._customerService.GetCustomerBySystemName(SystemCustomerNames.PdfConverter);
					}
				}*/

                // registered user?
                /*if (customer == null || customer.Deleted || !customer.Active)
                {
                    
                }
*/
                var customer = this._authenticationService.GetAuthenticatedCustomer();
                if (string.IsNullOrEmpty(customer))
                {
                    this._cachedCustomer = customer;
                }

                // impersonate user if required (currently used for 'phone order' support)
                /*if (customer != null && !customer.Deleted && customer.Active)
                {
                    int? impersonatedCustomerId = customer.GetAttribute<int?>(SystemCustomerAttributeNames.ImpersonatedCustomerId);
                    if (impersonatedCustomerId.HasValue && impersonatedCustomerId.Value > 0)
                    {
                        var impersonatedCustomer = this._customerService.GetCustomerById(impersonatedCustomerId.Value);
                        if (impersonatedCustomer != null && !impersonatedCustomer.Deleted && impersonatedCustomer.Active)
                        {
                            //set impersonated customer
                            this._originalCustomerIfImpersonated = customer;
                            customer = impersonatedCustomer;
                        }
                    }
                }*/

                // load guest customer
                /*if (customer == null || customer.Deleted || !customer.Active)
                {
                    var customerCookie = this.GetCustomerCookie();
                    if (customerCookie != null && !String.IsNullOrEmpty(customerCookie.Value))
                    {
                        Guid customerGuid;
                        if (Guid.TryParse(customerCookie.Value, out customerGuid))
                        {
                            var customerByCookie = this._customerService.GetCustomerByGuid(customerGuid);
                            if (customerByCookie != null &&
                                //this customer (from cookie) should not be registered
                                !customerByCookie.IsRegistered() &&
								//it should not be a built-in 'search engine' customer account
								!customerByCookie.IsSearchEngineAccount())
                                customer = customerByCookie;
                        }
                    }
                }*/

                // create guest if not exists
                /*if (customer == null || customer.Deleted || !customer.Active)
                {
                    customer = this._customerService.InsertGuestCustomer();
                }
*/

                // validation
                /*if (!customer.Deleted && customer.Active)
                {
                    this.SetCustomerCookie(customer.CustomerGuid);
                    this._cachedCustomer = customer;
                }*/
                return this._cachedCustomer;
            }

            set
            {
                this.SetCustomerCookie(value);
                this._cachedCustomer = value;
            }
        }

        /// <summary>
        ///     Gets or sets the original customer (in case the current one is impersonated)
        /// </summary>
        /// <summary>
        ///     Get or set current user working language
        /// </summary>
        /// <summary>
        ///     Get or set current user working currency
        /// </summary>
        /*public Currency WorkingCurrency
        {
            get
            {
                if (this._cachedCurrency != null)
                    return this._cachedCurrency;

                bool fixPrimaryStoreCurrency = false;
                Currency currency = null;
                // return primary store currency when we're in admin area/mode
                if (this.IsAdmin)
                {
                    currency = this._currencyService.GetCurrencyById(this._currencySettings.PrimaryStoreCurrencyId);
                }

                if (currency == null)
                {
                    // find current customer language
                    var customer = this.CurrentCustomer;

                    if (customer != null && !customer.IsSearchEngineAccount())
                    {
                        // search engines should always crawl by primary store currency
                        var customerCurrencyId = customer.GetAttribute<int?>(SystemCustomerAttributeNames.CurrencyId, this._attrService, this._storeContext.CurrentStore.Id);
                        if (customerCurrencyId.GetValueOrDefault() > 0)
                        {
                            currency = this.VerifyCurrency(this._currencyService.GetCurrencyById(customerCurrencyId.Value));
                            if (currency == null)
                            {
                                this._attrService.SaveAttribute<int?>(customer, SystemCustomerAttributeNames.CurrencyId, null, this._storeContext.CurrentStore.Id);
                            }
                        }
                    }

					// find currency by domain ending
					if (currency == null && this._httpContext != null && this._httpContext.Request != null && this._httpContext.Request.Url != null)
					{
						currency = this._currencyService
							.GetAllCurrencies(storeId: this._storeContext.CurrentStore.Id)
							.GetByDomainEnding(this._httpContext.Request.Url.Authority);
					}

                    // get PrimaryStoreCurrency
                    if (currency == null)
                    {
                        currency = this.VerifyCurrency(this._currencyService.GetCurrencyById(this._currencySettings.PrimaryStoreCurrencyId));
                        fixPrimaryStoreCurrency = (currency == null);
                    }

                    // get the first published currency for current store
                    if (currency == null)
                    {
                        var allStoreCurrencies = this._currencyService.GetAllCurrencies(storeId: this._storeContext.CurrentStore.Id);
                        if (allStoreCurrencies.Count > 0)
                        { 
                            currency = allStoreCurrencies.FirstOrDefault();
                        }
                    }
                }

				// if not found in currencies filtered by the current store, then return any currency
                if (currency == null)
                {
                    currency = this._currencyService.GetAllCurrencies().FirstOrDefault();
                }

                // no published currency available (fix it)
                if (currency == null)
                {
                    currency = this._currencyService.GetAllCurrencies(true).FirstOrDefault();
                    if (currency != null)
                    {
                        currency.Published = true;
                        this._currencyService.UpdateCurrency(currency);
                    }
                }

                if (fixPrimaryStoreCurrency)
                {
                    this._currencySettings.PrimaryStoreCurrencyId = currency.Id;
                    this._settingService.UpdateSetting(this._currencySettings, x => x.PrimaryStoreCurrencyId, true, this._storeContext.CurrentStore.Id);
                } 


                this._cachedCurrency = currency;
                return this._cachedCurrency;
            }
            set
            {
                int? id = value != null ? value.Id : (int?)null;
				this._attrService.SaveAttribute<int?>(this.CurrentCustomer, SystemCustomerAttributeNames.CurrencyId, id, this._storeContext.CurrentStore.Id);
                this._cachedCurrency = null;
			}
        }

        private Currency VerifyCurrency(Currency currency)
        {
            if (currency != null && !currency.Published)
            {
                return null;
            }
            return currency;
        }

        /// <summary>
        /// Get or set current tax display type
        /// </summary>
        public TaxDisplayType TaxDisplayType
        {
            get
            {
				return this.GetTaxDisplayTypeFor(this.CurrentCustomer, this._storeContext.CurrentStore.Id);
            }
            set
            {
                if (!this._taxSettings.AllowCustomersToSelectTaxDisplayType)
                    return;

				this._attrService.SaveAttribute(this.CurrentCustomer,
					 SystemCustomerAttributeNames.TaxDisplayTypeId,
					 (int)value, this._storeContext.CurrentStore.Id);
            }
        }

        public TaxDisplayType GetTaxDisplayTypeFor(Customer customer, int storeId)
        {
            if (this._cachedTaxDisplayType.HasValue)
            {
                return this._cachedTaxDisplayType.Value;
            }
			
            int? taxDisplayType = null;

            if (this._taxSettings.AllowCustomersToSelectTaxDisplayType && customer != null)
            {
		        taxDisplayType = customer.GetAttribute<int?>(SystemCustomerAttributeNames.TaxDisplayTypeId, storeId);
            }

            if (!taxDisplayType.HasValue && this._taxSettings.EuVatEnabled)
            {
				if (customer != null && this._taxService.Value.IsVatExempt(null, customer))
                {
                    taxDisplayType = (int)this.TaxDisplayType.ExcludingTax;
                }
            }

            if (!taxDisplayType.HasValue)
            {
                var customerRoles = customer.CustomerRoles;
                string key = string.Format(FrameworkCacheConsumer.CUSTOMERROLES_TAX_DISPLAY_TYPES_KEY, String.Join(",", customerRoles.Select(x => x.Id)), storeId);
                var cacheResult = this._cacheManager.Get(key, () =>
                {
                    var roleTaxDisplayTypes = customerRoles
                        .Where(x => x.TaxDisplayType.HasValue)
                        .OrderByDescending(x => x.TaxDisplayType.Value)
                        .Select(x => x.TaxDisplayType.Value);

                    if (roleTaxDisplayTypes.Any())
                    {
                        return (TaxDisplayType)roleTaxDisplayTypes.FirstOrDefault();
                    }

                    return this._taxSettings.TaxDisplayType;
                });

                taxDisplayType = (int)cacheResult;
            }

            this._cachedTaxDisplayType = (TaxDisplayType)taxDisplayType.Value;
            return this._cachedTaxDisplayType.Value;
        }*/
        public bool IsAdmin
        {
            get
            {
                if (!this._isAdmin.HasValue)
                {
                    this._isAdmin = this._httpContext.Request.IsAdminArea();
                }

                return this._isAdmin.Value;
            }

            set
            {
                this._isAdmin = value;
            }
        }

        /// <summary>
        /// The get customer cookie.
        /// </summary>
        /// <returns>
        /// The <see cref="HttpCookie"/>.
        /// </returns>
        protected HttpCookie GetCustomerCookie()
        {
            if (this._httpContext == null || this._httpContext.Request == null)
            {
                return null;
            }

            return this._httpContext.Request.Cookies[CustomerCookieName];
        }

        /// <summary>
        /// The set customer cookie.
        /// </summary>
        /// <param name="customerGuid">
        /// The customer guid.
        /// </param>
        protected void SetCustomerCookie(string customerGuid)
        {
            if (this._httpContext != null && this._httpContext.Response != null)
            {
                var cookie = new HttpCookie(CustomerCookieName);
                cookie.HttpOnly = true;
                cookie.Value = customerGuid;
                if (customerGuid == string.Empty)
                {
                    cookie.Expires = DateTime.Now.AddMonths(-1);
                }
                else
                {
                    var cookieExpires = 24 * 365; // TODO make configurable
                    cookie.Expires = DateTime.Now.AddHours(cookieExpires);
                }

                try
                {
                    if (this._httpContext.Response.Cookies[CustomerCookieName] != null)
                    {
                        this._httpContext.Response.Cookies.Remove(CustomerCookieName);
                    }
                }
                catch (Exception)
                {
                }

                this._httpContext.Response.Cookies.Add(cookie);
            }
        }

        /*
		[Obsolete("Use ILanguageService.IsPublishedLanguage() instead")]
		public bool IsPublishedLanguage(string seoCode, int storeId = 0)
		{
			return this._languageService.IsPublishedLanguage(seoCode, storeId);
		}

		[Obsolete("Use ILanguageService.GetDefaultLanguageSeoCode() instead")]
        public string GetDefaultLanguageSeoCode(int storeId = 0)
        {
			return this._languageService.GetDefaultLanguageSeoCode(storeId);
        }*/
    }
}